#include <iostream>
#include <string>
#include "rational.h"

Rational::Rational(int up_, int down_): up(up_), down(down_)
{
	checkSigns();
	divide();
}

Rational::Rational(const Rational& another)
{
	up = another.up;
	down = another.down;
}

Rational& Rational::operator= (const Rational &another)
{
	Rational tmp(another);
	swap(tmp);
	return *this;
}

void Rational::swap(Rational& another)
{
	std::swap(up,another.up);
	std::swap(down,another.down);
}


Rational::operator double()
{
	return ((double)up) / down;
}

int gcd(int a, int b)
{
	int r1 = a;
	int r2 = b;
	int r3 = r1 % r2;
	while(r3 != 0)
	{
		r1 = r2; r2 = r3; r3 = r1 % r2;
	}
	return r2;

}

void Rational::divide()
{
	if (down == 0)
	{
		std::cout << "Division by zero=(" << std::endl;
		return;
	}
	int res = gcd(up, down); 
	up /= res;
	down /= res;
}

void Rational::checkSigns()
{
	if ((up < 0 && down < 0) || (up > 0 && down < 0))
	{
		up *= (-1);
		down *= (-1);
	}
}

Rational Rational::operator++(int)
{
	Rational tmp(down, down);
	Rational result(*this);
	*this += tmp;
	return result;	
}

Rational& Rational::operator++()
{
	Rational tmp(down, down);
	*this += tmp;
	return *this;
}

Rational Rational::operator--(int)
{
	Rational tmp((-1)*down, down);
	Rational result(*this);
	*this += tmp;
	return result;	
}

Rational& Rational::operator--()
{
	Rational tmp((-1)*down, down);
	*this += tmp;
	return *this;
}

int Rational::getUp()
{
	return up;
}

int Rational::getDown()
{
	return down;
}

Rational Rational::operator*=(const Rational& a)
{
	up *= a.up;
	down *= a.down;
	checkSigns();
	divide();
	return *this;	
}

Rational Rational::operator/=(const Rational& a)
{
	up *= a.down;
	down *= a.up;
	checkSigns();
	divide();
	return *this;	
}

Rational Rational::operator+=(const Rational& a)
{
	up = up * a.down + a.up * down;
	down = a.down * down;
	checkSigns();
	divide();
	return *this;	
}

Rational Rational::operator-=(const Rational& a)
{
	up = up * a.down - a.up * down; 
	down = a.down * down;
	checkSigns();
	divide();
	return *this;	
}

bool operator==(const Rational& a, const Rational& b)
{
	return (a.up * b.down == a.down * b.up);
}

bool operator!=(const Rational& a, const Rational& b)
{
	return (a.up * b.down != a.down * b.up);
}

bool operator<(const Rational& a, const Rational& b)
{
	return (a.up * b.down < a.down * b.up);
}

bool operator<=(const Rational& a, const Rational& b)
{
	return (a.up * b.down <= a.down * b.up);
}

bool operator>(const Rational& a, const Rational& b)
{
	return !(a <= b);
}

bool operator>=(const Rational& a, const Rational& b)
{
	return !(a < b);
}

Rational operator*(const Rational &a, const Rational& b)
{
	Rational result(1,1);
	result *= a;
	result *= b;
	return result;
}

Rational operator/(const Rational &a, const Rational& b)
{
	Rational result(1,1);
	result /= a;
	result /= b;
	return result;
}

Rational operator+(const Rational &a, const Rational& b)
{
	Rational result(0,1);
	result += a;
	result += b;
	return result;
}

Rational operator-(const Rational &a, const Rational& b)
{
	Rational result(0,1);
	result -= a;
	result -= b;
	return result;
}

std::ostream& operator << (std::ostream& out, const Rational& r)
{
	if (r.up == 0)
	{
		return (out << "0" << std::endl);
	}
	if (r.down == 0)
	{
		return (out << "Infinity" << std::endl);
	}
	if (r.down == 1)
	{
		return (out << r.up << std::endl);
	}
	return (out << r.up << "/" << r.down << std::endl);
}
